package com.macro.mall.service.impl;


import cn.hutool.core.collection.CollUtil;
import com.github.pagehelper.PageHelper;
import com.macro.mall.bo.AdminDetails;
import com.macro.mall.dao.UmsAdminPermissionRelationDao;
import com.macro.mall.dao.UmsAdminRoleRelationDao;
import com.macro.mall.dto.UmsAdminParam;
import com.macro.mall.dto.UpdateAdminPasswordParam;
import com.macro.mall.service.UmsAdminService;
import com.macro.mall.service.UmsCacheService;
import com.macro.mapper.*;
import com.macro.model.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import com.macro.mall.util.JwtTokenUtil;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class UmsAdminServiceImpl implements UmsAdminService {
    private static final Logger LOGGER = LoggerFactory.getLogger(UmsAdminServiceImpl.class);

    @Autowired
    private JwtTokenUtil jwtTokenUtil;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private UmsAdminMapper adminMapper;
    @Autowired
    private UmsAdminRoleRelationMapper adminRoleRelationMapper;
    @Autowired
    private UmsAdminPermissionRelationMapper adminPermissionRelationMapper;
    @Autowired
    private UmsAdminLoginLogMapper adminLoginLogMapper;
    @Autowired
    private UmsAdminRoleRelationDao adminRoleDao;
    @Autowired
    private UmsAdminPermissionRelationDao adminPermissionRelationDao;
    @Autowired
    private UmsCacheService adminCacheService;


    @Override
    public UmsAdmin getUmsAdminByName(String username) {
        UmsAdmin admin = adminCacheService.getAdmin(username);
        if(admin!=null) return  admin;

        UmsAdminExample example = new UmsAdminExample();
        example.createCriteria().andUsernameEqualTo(username);
        List<UmsAdmin> umsAdmins = adminMapper.selectByExample(example);
        if (umsAdmins != null && umsAdmins.size() > 0){
            admin = umsAdmins.get(0);
            adminCacheService.setAdmin(admin);
            return admin;
        }

       // throw new UsernameNotFoundException("没有该用户");
        return null;
    }

    @Override
    public UmsAdmin register(UmsAdminParam umsAdminParam) {
        //判断是否已经存在该用户
        UmsAdminExample example = new UmsAdminExample();
        example.createCriteria().andUsernameEqualTo(umsAdminParam.getUsername());
        List<UmsAdmin> umsAdmins = adminMapper.selectByExample(example);
        if (umsAdmins.isEmpty())
            return null;
        UmsAdmin user = new UmsAdmin();
        BeanUtils.copyProperties(umsAdminParam, user);  //将dto的属性值赋给user对象
        String encodePassword = passwordEncoder.encode(user.getPassword());  //对密码进行加密
        user.setCreateTime(new Date());
        user.setStatus(1);
        user.setPassword(encodePassword);
        adminMapper.insert(user);
        return user;
    }

    @Override
    public String login(String username, String password) {
        String token = null;
        try {
            UserDetails userDetails = loadUserByUsername(username);
            if(!passwordEncoder.matches(password,userDetails.getPassword()))
                throw new BadCredentialsException("密码错误");
            UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
            SecurityContextHolder.getContext().setAuthentication(authentication);
            token = jwtTokenUtil.generateToken(userDetails);
        }catch (AuthenticationException e){
            LOGGER.warn("登录异常:{}", e.getMessage());
        }
        return token;
    }

    @Override
    public String refreshToken(String oldToken) {

        return jwtTokenUtil.refreshHeadToken(oldToken);
    }

    @Override
    public UmsAdmin getItemById(Long id) {
        return adminMapper.selectByPrimaryKey(id);
    }

    @Override
    public List<UmsAdmin> list(String keyword, Integer pageNumber, Integer pageSize) {
        PageHelper.startPage(pageNumber, pageSize);
        UmsAdminExample example = new UmsAdminExample();
        UmsAdminExample.Criteria criteria = example.createCriteria();
        if (!StringUtils.isEmpty(keyword)) {
            criteria.andUsernameLike("%" + keyword + "%");
            example.or(example.createCriteria().andNickNameLike("%" + keyword + "%"));
            // 等价于
            // example.or().andNickNameLike("%" + keyword + "%")
        }
        return adminMapper.selectByExample(example);
    }

    @Override
    public int update(Long id, UmsAdmin admin) {
        admin.setId(id);
        UmsAdmin oldAdmin = adminMapper.selectByPrimaryKey(id);
        // 判断密码是否相同
        if (passwordEncoder.matches(admin.getPassword(), oldAdmin.getPassword()))
            admin.setPassword(null);
        else  // 不相同的话，加密后更新
            admin.setPassword(passwordEncoder.encode(admin.getPassword()));

        int count = adminMapper.updateByPrimaryKeySelective(admin);
        adminCacheService.delAdmin(id);
        return count;
    }

    @Override
    public int delete(Long id) {
        adminCacheService.delAdmin(id);
        int count = adminMapper.deleteByPrimaryKey(id);
        adminCacheService.delResourceList(id);
        return count;
    }

    @Override
    public int updateRole(Long adminId, List<Long> roleIds) {
        int count = roleIds == null ? 0 : roleIds.size();
        UmsAdminRoleRelationExample example = new UmsAdminRoleRelationExample();
        example.createCriteria().andAdminIdEqualTo(adminId);
        // 先删除原来的关系
        adminRoleRelationMapper.deleteByExample(example);
        List<UmsAdminRoleRelation> list = new ArrayList<>();
        if (!CollectionUtils.isEmpty(roleIds)) {
            for (Long roleId : roleIds) {
                UmsAdminRoleRelation adminRoleRelation = new UmsAdminRoleRelation();
                adminRoleRelation.setAdminId(adminId);
                adminRoleRelation.setRoleId(roleId);
                list.add(adminRoleRelation);
            }
        adminRoleDao.insertList(list);
        }
        adminCacheService.delResourceList(adminId);
        return count;
    }

    @Override
    public List<UmsRole> getRoleList(Long adminId) {
        return adminRoleDao.getRoleList(adminId);
    }

    @Override
    public List<UmsResource> getResourceList(Long adminId) {
        List<UmsResource> resourceList = adminCacheService.getResourceList(adminId);
        if(CollUtil.isNotEmpty(resourceList)){
            return  resourceList;
        }
        resourceList = adminRoleDao.getResourceList(adminId);
        if(CollUtil.isNotEmpty(resourceList)){
            adminCacheService.setResourceList(adminId,resourceList);
        }
        return resourceList;
    }

    @Override
    public int updatePermission(Long adminId, List<Long> permissionIds) {
        UmsAdminPermissionRelationExample example = new UmsAdminPermissionRelationExample();
        example.createCriteria().andAdminIdEqualTo(adminId);
        // 删除原来的权限
        adminPermissionRelationMapper.deleteByExample(example);
        // 获得该用户角色所有的权限.
        List<UmsPermission> permissionList = adminRoleDao.getRolePermissionList(adminId);
        List<Long> ids = permissionList.stream().map(UmsPermission::getId).collect(Collectors.toList());
        if(!CollectionUtils.isEmpty(permissionIds)){
            List<UmsAdminPermissionRelation> relations = new ArrayList<>();
            // + 权限
            List<Long> addPermission = permissionIds.stream().filter(id -> !ids.contains(id)).collect(Collectors.toList());
            // - 权限
            List<Long> subPermission = ids.stream().filter(id -> !permissionIds.contains(id)).collect(Collectors.toList());

            relations.addAll(convert(adminId,1,addPermission));
            relations.addAll(convert(adminId,-1,subPermission));
            return adminPermissionRelationDao.insertList(relations);
        }
        return 0;
    }

    //helper
    private List<UmsAdminPermissionRelation> convert(Long adminId,Integer type,List<Long> ids){
        return ids.stream().map(id -> {
            UmsAdminPermissionRelation relation = new UmsAdminPermissionRelation();
            relation.setPermissionId(id);
            relation.setAdminId(adminId);
            relation.setType(type);
            return relation;
        }).collect(Collectors.toList());
    }


    @Override
    public List<UmsPermission> getPermissionList(Long adminId) {
        return adminRoleDao.getPermissionList(adminId);
    }

    @Override
    public int updatePassword(UpdateAdminPasswordParam updatePasswordParam) {
        if(StringUtils.isEmpty(updatePasswordParam.getUsername())
            || StringUtils.isEmpty(updatePasswordParam.getNewPassword())
            || StringUtils.isEmpty(updatePasswordParam.getOldPassword()))
            return -1;   //参数错误
        UmsAdmin user = getUmsAdminByName(updatePasswordParam.getUsername());
        if(user == null)
            return -2;   // 无此用户
        if(!passwordEncoder.matches(updatePasswordParam.getOldPassword(),user.getPassword()))
            return -3;   // 密码错误
        String encodePassword = passwordEncoder.encode(updatePasswordParam.getNewPassword());
        user.setPassword(encodePassword);
        adminMapper.updateByPrimaryKeySelective(user);
        adminCacheService.delAdmin(user.getId());

        return 1;
    }

    @Override
    public UserDetails loadUserByUsername(String username) {
        UmsAdmin user = getUmsAdminByName(username);
        if (user == null)
            throw new UsernameNotFoundException("用户名或密码错误");

        // 获取该用户所拥有的资源集合
        List<UmsResource> resourceList = adminRoleDao.getResourceList(user.getId());

        return new AdminDetails(user,resourceList);
    }
}
